Do you know about Philosophy? If you read a lot about them, that’s very cool. Hope you find this article helpful from the perspective of data analysis and visualization. If you are not very familiar with this subject (just as I am), don’t worry. You will get the first impression on each main school of Philosophy.

The first part of the data story is about analysis of the whole corpus of Philosophy. It will bring you an overview of the data set we are currently working on. The second part focuses on sentiment analysis of two interesting schools: Capitalism and Communism.

Part 1: Data set overview. Let’s look at the whole curpus!

Preparation

Setting up environment

This report is prepared with the following environmental settings.

print(R.version)
               _                           
platform       x86_64-apple-darwin17.0     
arch           x86_64                      
os             darwin17.0                  
system         x86_64, darwin17.0          
status                                     
major          4                           
minor          0.3                         
year           2020                        
month          10                          
day            10                          
svn rev        79318                       
language       R                           
version.string R version 4.0.3 (2020-10-10)
nickname       Bunny-Wunnies Freak Out     

Load the packages and source files

We don’t need all the packages listed there. They covers the functionality from generating, cleaning the original data set, to data analysis, manipulation, visualization, and sentiment analysis etc.. We mainly focus on the latter part of the functions.

I wrote two functions f.clean.corpus and f.make.tdm in the ../lib/wordcloudFuncs.R since we would generate many word clouds using these wrapped functions rather than writing similar, redundant code.

packages.used=c("rvest", "tibble", 
                "sentimentr", "gplots", "dplyr",
                "tm", "syuzhet", "factoextra", 
                "beeswarm", "scales", "RColorBrewer",
                "RANN", "topicmodels", "stringr", 
                "ggridges", "wordcloud", "wordcloud2",
                "tidytext", "knitr", "tidyverse")
# check packages that need to be installed.
packages.needed=setdiff(packages.used, 
                        intersect(installed.packages()[,1], 
                                  packages.used))
# install additional packages
if(length(packages.needed)>0){
  install.packages(packages.needed, dependencies = TRUE)
}
# load packages
library("rvest")
library("tibble")
library("syuzhet")
library("sentimentr")
library("gplots")
library("dplyr")
library("tm")
library("syuzhet")
library("factoextra")
library("beeswarm")
library("scales")
library("RColorBrewer")
library("RANN")
library("tm")
library("topicmodels")
library("stringr")
library("ggplot2")
#library("ggridges")
#library("viridis")
library("wordcloud")
library("wordcloud2")
library("tidytext")
library("knitr")
library("tidyverse")

#source("../lib/plotstacked.R")
source("../lib/speechFuncs.R")
source("../lib/wordcloudFuncs.R")

Load the dataset

The data set ../data/philosophy_data.csv contains 360808 sentences taken from 51 texts spanning 13 major schools of the history of philosophy. You can find more details about it in https://www.kaggle.com/kouroshalizadeh/history-of-philosophy.

file<-'../data/philosophy_data.csv'
full_data <- read.csv(file)
full_data <- full_data %>% 
  mutate(word.count = f.word_count(sentence_spacy))
# sentence.list is generated from the chunk {r generate sentence.list}. This will 
# cost 25-30 minutes. To save your time, you can simply use it.
# Feel free if you don't want to run {r generate sentence.list}
subfile <- '../output/sentence.list.csv'
sentence.list <- read.csv(subfile)

reduced_data = full_data %>% select(title, author, school, sentence_spacy, original_publication_date, sentence_length, word.count)

#trial_data <- reduced_data[1:1000,]
data <- reduced_data %>% filter(school == "capitalism" | school == "communism")

Task 1: Investigate the length of sentences of different schools

The word “philosophy” literally means the “love” (Philo in Greek) of “wisdom” (Sophia). As an outsider, I always think philosophy is a profound, opaque subject which is very challenging to learn. I believe that many people like me would presuppose that sentences in philosophy texts tend to be longer than usual sentences. Hence, let’s begin by investigating the the length of sentences of different schools.

From this bar plot, we see that empiricism, capitalism, and german_idealism are the three schools with longest sentences(longer than 30 words); Nietzsche, analytic, plato are the three schools with relative short sentences(a big longer than 20 words). “In general, an average of 15 to 20 words is effective for most technical communication.” –By James Scott. Hence, we see that even the school with shortest mean length of sentences still has mean length longer than usual written sentences’ length.

data.byschool <- reduced_data %>% group_by(school) %>%
  summarise(meanlength = mean(word.count)) %>%
  arrange(meanlength)
  
g1 <- data.byschool %>% ggplot(aes(x = reorder(school, meanlength), y = meanlength, fill = school)) + 
  geom_bar(stat = "identity") +
  labs(
    title = "Bar plot: mean length of sentences(word count) of different schools",
    x = "Schools",
    y = "Mean Length of Sentences"
  ) +
  coord_flip()

g1

In addition to the mean length of sentences, this violin + box plot will show more details of actual distributions of sentence length. All the schools have outliers(black dots) on the right side of violin plot, which means they all have some very long sentences which might be abstruse or rigorous.

data.byschool <- reduced_data %>% group_by(school) 
g2 <- data.byschool %>% ggplot(aes(x = school, y = word.count, fill = school)) +
  geom_violin(alpha = 0.5) +
  #geom_point(position = position_jitter(seed = 1, width = 0.2)) +
  theme(legend.position = "none") +
  geom_boxplot(width=.1) +
  labs(
    title = "violin plot + box plot: spread of sentences' length \n of different schools",
    x = "Schools",
    y = "Length of Sentences"
  ) +
  coord_flip()

g2

Task 2: Investigate the frequently mentioned words

What we did in task 1 would generally represents the shape and format of sentences in different schools. Now, let’s dig into the contents and topics.

Let’s first have an overview of frequency of words in the whole corpus. A wordcloud would be an optimal method for word frequency visualization.

Prepare corpus

Put all the sentences(360808 observations) into a Large SimpleCorpus docs.

Clean corpus and make document-term-matrices

f.clean.corpus cleans the docs by lowering sentences, removing numbers, punctuations, white spaces, common stop words in English, and an additional set of words rm_words which contains words of my choice. f.make.tdm makes the docs ready to make a wordcloud. See details in ../lib/wordcloudFuncs.R.

rm_words = c('also', 'areas', 'can', 'etc', 'get', 'just', 'like',
'lot', 'many', 'may', 'need', 'one', 's', 'set', 't',
'time', 'us', 'use', 'way', 'well', 'will', 'b', 'e',
'g', 'less', 'give', 'tell', 'im', 'take', 'coming',
'say', 'really', 'must')

docs <- f.clean.corpus(docs)
tdm.overall <- f.make.tdm(docs)

Make a wordcloud of the whole corpus

wordcloud(tdm.overall$term, tdm.overall$`sum(count)`,
          scale=c(5,0.8),
          max.words=200,
          min.freq=1,
          random.order=FALSE,
          rot.per=0.3,
          random.color=FALSE,
          colors=brewer.pal(8,"Dark2"))

Now let’s see the word clouds of different schools.

The method is similar to above. You can read the actual code in ../doc/Philosophy data story.Rmd.

Capitalism:

Empiricism:

German_idealism:

Continental:

Rationalism:

Aristotle:

Feminism:

Communism:

Phenomenology:

stoicism: Thou is an old-fashioned, poetic, or religious word for ‘you’ when you are talking to only one person. It is used as the subject of a verb. In rm_words, I include “you” as it is an insignificant word. But “thou” brings a specific context and style of a philosophy text.

Analytic:

Nietzsche:

Plato:

From these wordclouds, you can find out what words are frequently mentioned in each school of philosophy. And you can imagine what topics they focus on. For my personal interest, I especially analyze the wordclouds of capitalism and communism. Many of us know they are contrast to some degree, but cannot state the differences clearly. I originally expected their wordclouds would be very different. However, both of them mentioned a lot about “value”, “labour”, “capital”, “commodities”, “price”, “wages”, “trade” etc.. The degree of similarity exceeded my expectation, and I began to speculate that they might often talk about similar topic but with contrast ideas. Here, we can refer to Adam Smith, the renowned Scottish Economist(on the side of capitalism), and Karl Marx, a famous Philosopher, and Sociologist, from Germany(on the side of communism), to see the difference of capitalism and communism:

“Capitalism is an economic system in which the trade and industry of the economy is owned and controlled by private individuals, to make profit.”

“Communism refers to social system in which country’s trade and industry are controlled by the community and the share of each individual relies on his ability and needs.”

For more detail, please refer to Difference Between Capitalism and Communism In part 2, we will do some sentiment analysis on these two schools of philosophy, and try to explore something interesting and uncovered by the above article.

Part 2: Sentiment analysis on capitalism and communism

During this part, we apply sentiment analysis using NRC Word-Emotion Association Lexicon. For each sentence, this method would give a score for each sentiment(“anger”, “anticipation”, “disgust”, “fear”, “joy”, “sadness”, “surprise”, “trust”, “negative”, “positive”) according to The NRC Emotion Lexicon, a list of English words and their associations with basic emotions.

task 3 : Investigate and compare emotions between capitalism and communism

generate sentence.list

sentence.list is a subset of the whole corpus. It only includes sentences with school of capitalism or communism. And we will generat their sentiment score and append them on the right of the data set(12 columns: 10 columns of sentiment, 1 column of sentence id, 1 column of word count). It will cost 25-30 minutes to generate sentence.list, so I commented this r chunk and you can use it from “../lib/wordcloudFuncs.R”.

# sentence.list=NULL
# 
# for(i in 1:nrow(data)){
#   sentences <- data$sentence_spacy[i]
#   if(length(sentences)>0){
#     emotions=get_nrc_sentiment(sentences)
#     #word.count=word_count(sentences)
#     # colnames(emotions)=paste0("emo.", colnames(emotions))
#     # in case the word counts are zeros?
#     #emotions=diag(1/(trial_data$sentence_length[1]+0.01))%*%as.matrix(emotions)
#     emotions = as.matrix(emotions)
#     sentence.list=rbind(sentence.list,
#                         cbind(data[i,],
#                               sentences=as.character(sentences),
#                               #word.count,
#                               emotions,
#                               sent.id=i
#                               )
#     )
#   }
# }
#
# sentence.list <- sentence.list %>% left_join(data) #join the word.count into sentence.list
#write.csv(sentence.list,"/Users/jiuruwang/Documents/GitHub/spring-2022-prj1-jrwang0810/output/sentence.list.csv")
names(sentence.list)
 [1] "X.1"                       "X"                         "title"                    
 [4] "author"                    "school"                    "sentence_spacy"           
 [7] "original_publication_date" "sentence_length"           "sentences"                
[10] "anger"                     "anticipation"              "disgust"                  
[13] "fear"                      "joy"                       "sadness"                  
[16] "surprise"                  "trust"                     "negative"                 
[19] "positive"                  "sent.id"                   "word.count"               

Find out emotionally charged sentences

Here we can see some typical short sentences with strong sentiment.

Capitalism:

emotions.types=c("anticipation", "joy", "surprise", "trust",
                 "anger", "disgust", "fear", "sadness", "negative", "positive")

speech.df=tbl_df(sentence.list) %>%
  filter(school == "capitalism", word.count < 20) %>%
  select(sentences, anger:positive)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
 [1] "This complaint, however, of the scarcity of money, is not always confined to improvident spendthrifts."                                        
 [2] "This money, however, was for a long time, received at the exchequer, by weight, and not by tale."                                              
 [3] "Bankruptcy is, perhaps, the greatest and most humiliating calamity which can befal an innocent man."                                           
 [4] "Poverty, though it no doubt discourages, does not always prevent, marriage."                                                                   
 [5] "The cheapness and plenty of good land encourage improvement, and enable the proprietor to pay those high wages."                               
 [6] "below its standard weight, the bank would, in this case, have lost only one percent."                                                          
 [7] "Its nominal price was a good deal lower than at present."                                                                                      
 [8] "The cheapness and plenty of good land encourage improvement, and enable the proprietor to pay those high wages."                               
 [9] "Not only ignorance and misinformation, but friendship, party animosity, and private resentment, are said frequently to mislead such assessors."
[10] "The cheapness and plenty of good land encourage improvement, and enable the proprietor to pay those high wages."                               

Communism:


speech.df=tbl_df(sentence.list) %>%
  filter(school == "communism", word.count < 20) %>%
  select(sentences, anger:positive)
speech.df=as.data.frame(speech.df)
as.character(speech.df$sentences[apply(speech.df[,-1], 2, which.max)])
 [1] "In actual history it is notorious that conquest, enslavement, robbery, murder, briefly force, play the great part."        
 [2] "The new nobility was the child of its time, for which money was the power of all powers."                                  
 [3] "Or perhaps Bastiat means, that a mode of production based on slavery is based on a system of plunder."                     
 [4] "In actual history it is notorious that conquest, enslavement, robbery, murder, briefly force, play the great part."        
 [5] "the rich grow rapidly richer, whilst there is no perceptible advance in the comfort enjoyed by the industrial classes."    
 [6] "One old woman was burnt to death in the flames of the hut, which she refused to leave."                                    
 [7] "Then one use value is just as good as another, provided only it be present in sufficient quantity."                        
 [8] "Dr. Simon, medical officer to the Privy Council, chose for this work the above mentioned Dr. Smith."                       
 [9] "In actual history it is notorious that conquest, enslavement, robbery, murder, briefly force, play the great part."        
[10] "In order to be fully prepared for his task, the working class revolutionary must also become a professional revolutionary."

Clustering of emotions

Here are the heatmaps of correlation matrix about sentiment respectively in capitalism and communism. Please note that the red regions means a strong positive correlation(close to but less or equal to 1) of two sentiment, blue regions means nearly no correlation(close to but more or equal to 0), and a white region shows some correlation.

Capitalism:

heatmap.2(cor(sentence.list%>%filter(school=="capitalism")%>%select(anger:positive)), 
          scale = "none", 
          col = bluered(100), , margin=c(6, 6), key=F,
          trace = "none", density.info = "none")
par(mar=c(4, 6, 2, 1))

Communism:

heatmap.2(cor(sentence.list%>%filter(school=="communism")%>%select(anger:positive)), 
          scale = "none", 
          col = bluered(100), , margin=c(6, 6), key=F,
          trace = "none", density.info = "none")
par(mar=c(4, 6, 2, 1))

We see that for both school, their heatmap are very similar. It makes sense that most positive sentiments are uncorrelated with most negative sentiment. But it is hard to tell any significant difference between two schools. So, let’s go with some more intuitionistic methods.

Bar plot and Pie chart of emotions

Here are the bar plot of mean score of each sentiment, and the pie chart of percentage of each sentiment. In the bar plot, all positive-related sentiments are in orange, and all negative-related sentiments are in their appropriate color.

sentence.list.capitalism <- sentence.list %>% filter(school=="capitalism")
emo.means1=colMeans(select(sentence.list.capitalism, anger:positive)>0.01)
col.use1=c("red2", "darkgoldenrod1", "chartreuse3","blueviolet", "darkgoldenrod1", "dodgerblue3", "darkgoldenrod1", "darkgoldenrod1", "black", "darkgoldenrod1")
barplot(emo.means1[order(emo.means1)], las=2, col=col.use1[order(emo.means1)], horiz=T,
        cex.names=0.7, main="Capitalism")

sentiment.df1 <- data.frame(
  group=c("anger", "anticipation", "disgust","fear", "joy", "sadness", "surprise", "trust", "negative", "positive"),
  value=emo.means1
)

sentiment.df1 <- sentiment.df1 %>% 
  mutate(perc = value / sum(value)) %>% 
  arrange(perc) %>%
  mutate(labels = scales::percent(perc))


ggplot(sentiment.df1, aes(x="", y=perc, fill=group)) +
  geom_bar(stat="identity", width=1, color="white") +
  coord_polar("y", start=0) +
  geom_text(aes(label = labels), 
            position = position_stack(vjust = 0.5),
            show.legend = FALSE,
            color = "white", size=3) +
  scale_fill_brewer(palette="Spectral") +
  labs(
    title = "Percentage of the sentiment in Capitalism",
    x = "",
    y = "",
  )

sentence.list.communism <- sentence.list %>% filter(school=="communism")
emo.means2=colMeans(select(sentence.list.communism, anger:positive)>0.01)
col.use2=c("red2", "darkgoldenrod1", "chartreuse3","blueviolet", "darkgoldenrod1", "dodgerblue3", "darkgoldenrod1", "darkgoldenrod1", "black", "darkgoldenrod1")
barplot(emo.means2[order(emo.means2)], las=2, col=col.use2[order(emo.means2)], horiz=T,
        cex.names=0.7, main="Communism")

sentiment.df2 <- data.frame(
  group=c("anger", "anticipation", "disgust","fear", "joy", "sadness", "surprise", "trust", "negative", "positive"),
  value=emo.means2
)

sentiment.df2 <- sentiment.df2 %>% 
  mutate(perc = value / sum(value)) %>% 
  arrange(perc) %>%
  mutate(labels = scales::percent(perc))


ggplot(sentiment.df2, aes(x="", y=perc, fill=group)) +
  geom_bar(stat="identity", width=1, color="white") +
  coord_polar("y", start=0) +
  geom_text(aes(label = labels), 
            position = position_stack(vjust = 0.5),
            show.legend = FALSE,
            color = "white", size=3) +
  scale_fill_brewer(palette="Spectral") +
  labs(
    title = "Percentage of the sentiment in Communism",
    x = "",
    y = "",
  )

These plots still looks similar, but now we can find some interesting pattern. In capitalism, joy is much higher than fear; but joy is lower than fear in communism. It looks like sentences in communism are more likely to express fear than in capitalism. However, is this the truth?

Let’s compare the mean sentiment score of capitalism and communism by combining the two bar plot. Here we find a really interesting point—— fear score is actually slightly higher in capitalism than in communism. So what happened? The truth is that sentences in capitalism are mostly more emotional than sentences in communism. The only exception is disgust.

sentiment.df.all <- data.frame(
  group=c("anger", "anticipation", "disgust","fear", "joy", "sadness", "surprise", "trust", "negative", "positive"),
  capitalism=emo.means1,
  communism=emo.means2
)

sentiment.df.all.long <- sentiment.df.all %>% pivot_longer(c("capitalism", "communism"))

g3 <- sentiment.df.all.long %>% ggplot(aes(x = group, y = value, fill = name)) +
  geom_col(position = "dodge") +
  labs(
    x = "",
    y = "mean score of sentiment",
    title = "Sentiment comparison: Capitalism vs. Communism"
  )

g3

Just for your curious, I made a bar plot of mean sentiment score for each authors in capitalism and communism. It is really funny to see that Marx is such an impassive person.

That’s all of the philosophy data story. I hope you have fun reading it!

LS0tCnRpdGxlOiAiSW52ZXN0aWdhdGluZyBkaWZmZXJlbnQgc2Nob29scyBvZiBQaGlsb3NvcGh5LS1DYXBpdGFsaXNtIHZzLiBDb21tdW5pc20iCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkRvIHlvdSBrbm93IGFib3V0IFBoaWxvc29waHk/IElmIHlvdSByZWFkIGEgbG90IGFib3V0IHRoZW0sIHRoYXQncyB2ZXJ5IGNvb2wuIEhvcGUgeW91IGZpbmQgdGhpcyBhcnRpY2xlIGhlbHBmdWwgZnJvbSB0aGUgcGVyc3BlY3RpdmUgb2YgZGF0YSBhbmFseXNpcyBhbmQgdmlzdWFsaXphdGlvbi4gSWYgeW91IGFyZSBub3QgdmVyeSBmYW1pbGlhciB3aXRoIHRoaXMgc3ViamVjdCAoanVzdCBhcyBJIGFtKSwgZG9uJ3Qgd29ycnkuIFlvdSB3aWxsIGdldCB0aGUgZmlyc3QgaW1wcmVzc2lvbiBvbiBlYWNoIG1haW4gc2Nob29sIG9mIFBoaWxvc29waHkuIAoKVGhlIGZpcnN0IHBhcnQgb2YgdGhlIGRhdGEgc3RvcnkgaXMgYWJvdXQgYW5hbHlzaXMgb2YgdGhlIHdob2xlIGNvcnB1cyBvZiBQaGlsb3NvcGh5LiBJdCB3aWxsIGJyaW5nIHlvdSBhbiBvdmVydmlldyBvZiB0aGUgZGF0YSBzZXQgd2UgYXJlIGN1cnJlbnRseSB3b3JraW5nIG9uLiBUaGUgc2Vjb25kIHBhcnQgZm9jdXNlcyBvbiBzZW50aW1lbnQgYW5hbHlzaXMgb2YgdHdvIGludGVyZXN0aW5nIHNjaG9vbHM6IENhcGl0YWxpc20gYW5kIENvbW11bmlzbS4gCgojIFBhcnQgMTogRGF0YSBzZXQgb3ZlcnZpZXcuIExldCdzIGxvb2sgYXQgdGhlIHdob2xlIGN1cnB1cyEKCiMjIFByZXBhcmF0aW9uCiMjIyMgU2V0dGluZyB1cCBlbnZpcm9ubWVudAoKYGBge3Igc2V0dXAsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKClRoaXMgcmVwb3J0IGlzIHByZXBhcmVkIHdpdGggdGhlIGZvbGxvd2luZyBlbnZpcm9ubWVudGFsIHNldHRpbmdzLgoKYGBge3J9CnByaW50KFIudmVyc2lvbikKYGBgCiMjIyMgTG9hZCB0aGUgcGFja2FnZXMgYW5kIHNvdXJjZSBmaWxlcwoKV2UgZG9uJ3QgbmVlZCBhbGwgdGhlIHBhY2thZ2VzIGxpc3RlZCB0aGVyZS4gVGhleSBjb3ZlcnMgdGhlIGZ1bmN0aW9uYWxpdHkgZnJvbSBnZW5lcmF0aW5nLCBjbGVhbmluZyB0aGUgb3JpZ2luYWwgZGF0YSBzZXQsIHRvIGRhdGEgYW5hbHlzaXMsIG1hbmlwdWxhdGlvbiwgdmlzdWFsaXphdGlvbiwgYW5kIHNlbnRpbWVudCBhbmFseXNpcyBldGMuLiBXZSBtYWlubHkgZm9jdXMgb24gdGhlIGxhdHRlciBwYXJ0IG9mIHRoZSBmdW5jdGlvbnMuCgpJIHdyb3RlIHR3byBmdW5jdGlvbnMgKipmLmNsZWFuLmNvcnB1cyoqIGFuZCAqKmYubWFrZS50ZG0qKiBpbiB0aGUgKi4uL2xpYi93b3JkY2xvdWRGdW5jcy5SKiBzaW5jZSB3ZSB3b3VsZCBnZW5lcmF0ZSBtYW55IHdvcmQgY2xvdWRzIHVzaW5nIHRoZXNlIHdyYXBwZWQgZnVuY3Rpb25zIHJhdGhlciB0aGFuIHdyaXRpbmcgc2ltaWxhciwgcmVkdW5kYW50IGNvZGUuIAoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBhY2thZ2VzLnVzZWQ9YygicnZlc3QiLCAidGliYmxlIiwgCiAgICAgICAgICAgICAgICAic2VudGltZW50ciIsICJncGxvdHMiLCAiZHBseXIiLAogICAgICAgICAgICAgICAgInRtIiwgInN5dXpoZXQiLCAiZmFjdG9leHRyYSIsIAogICAgICAgICAgICAgICAgImJlZXN3YXJtIiwgInNjYWxlcyIsICJSQ29sb3JCcmV3ZXIiLAogICAgICAgICAgICAgICAgIlJBTk4iLCAidG9waWNtb2RlbHMiLCAic3RyaW5nciIsIAogICAgICAgICAgICAgICAgImdncmlkZ2VzIiwgIndvcmRjbG91ZCIsICJ3b3JkY2xvdWQyIiwKICAgICAgICAgICAgICAgICJ0aWR5dGV4dCIsICJrbml0ciIsICJ0aWR5dmVyc2UiKQojIGNoZWNrIHBhY2thZ2VzIHRoYXQgbmVlZCB0byBiZSBpbnN0YWxsZWQuCnBhY2thZ2VzLm5lZWRlZD1zZXRkaWZmKHBhY2thZ2VzLnVzZWQsIAogICAgICAgICAgICAgICAgICAgICAgICBpbnRlcnNlY3QoaW5zdGFsbGVkLnBhY2thZ2VzKClbLDFdLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhY2thZ2VzLnVzZWQpKQojIGluc3RhbGwgYWRkaXRpb25hbCBwYWNrYWdlcwppZihsZW5ndGgocGFja2FnZXMubmVlZGVkKT4wKXsKICBpbnN0YWxsLnBhY2thZ2VzKHBhY2thZ2VzLm5lZWRlZCwgZGVwZW5kZW5jaWVzID0gVFJVRSkKfQojIGxvYWQgcGFja2FnZXMKbGlicmFyeSgicnZlc3QiKQpsaWJyYXJ5KCJ0aWJibGUiKQpsaWJyYXJ5KCJzeXV6aGV0IikKbGlicmFyeSgic2VudGltZW50ciIpCmxpYnJhcnkoImdwbG90cyIpCmxpYnJhcnkoImRwbHlyIikKbGlicmFyeSgidG0iKQpsaWJyYXJ5KCJzeXV6aGV0IikKbGlicmFyeSgiZmFjdG9leHRyYSIpCmxpYnJhcnkoImJlZXN3YXJtIikKbGlicmFyeSgic2NhbGVzIikKbGlicmFyeSgiUkNvbG9yQnJld2VyIikKbGlicmFyeSgiUkFOTiIpCmxpYnJhcnkoInRtIikKbGlicmFyeSgidG9waWNtb2RlbHMiKQpsaWJyYXJ5KCJzdHJpbmdyIikKbGlicmFyeSgiZ2dwbG90MiIpCiNsaWJyYXJ5KCJnZ3JpZGdlcyIpCiNsaWJyYXJ5KCJ2aXJpZGlzIikKbGlicmFyeSgid29yZGNsb3VkIikKbGlicmFyeSgid29yZGNsb3VkMiIpCmxpYnJhcnkoInRpZHl0ZXh0IikKbGlicmFyeSgia25pdHIiKQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQoKI3NvdXJjZSgiLi4vbGliL3Bsb3RzdGFja2VkLlIiKQpzb3VyY2UoIi4uL2xpYi9zcGVlY2hGdW5jcy5SIikKc291cmNlKCIuLi9saWIvd29yZGNsb3VkRnVuY3MuUiIpCgpgYGAKCiMjIyMgTG9hZCB0aGUgZGF0YXNldAoKVGhlIGRhdGEgc2V0ICouLi9kYXRhL3BoaWxvc29waHlfZGF0YS5jc3YqIGNvbnRhaW5zIDM2MDgwOCBzZW50ZW5jZXMgdGFrZW4gZnJvbSA1MSB0ZXh0cyBzcGFubmluZyAxMyBtYWpvciBzY2hvb2xzIG9mIHRoZSBoaXN0b3J5IG9mIHBoaWxvc29waHkuIFlvdSBjYW4gZmluZCBtb3JlIGRldGFpbHMgYWJvdXQgaXQgaW4gW2h0dHBzOi8vd3d3LmthZ2dsZS5jb20va291cm9zaGFsaXphZGVoL2hpc3Rvcnktb2YtcGhpbG9zb3BoeV0oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9rb3Vyb3NoYWxpemFkZWgvaGlzdG9yeS1vZi1waGlsb3NvcGh5KS4gCgpgYGB7ciByZWFkIGRhdGEsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmZpbGU8LScuLi9kYXRhL3BoaWxvc29waHlfZGF0YS5jc3YnCmZ1bGxfZGF0YSA8LSByZWFkLmNzdihmaWxlKQpmdWxsX2RhdGEgPC0gZnVsbF9kYXRhICU+JSAKICBtdXRhdGUod29yZC5jb3VudCA9IGYud29yZF9jb3VudChzZW50ZW5jZV9zcGFjeSkpCiMgc2VudGVuY2UubGlzdCBpcyBnZW5lcmF0ZWQgZnJvbSB0aGUgY2h1bmsge3IgZ2VuZXJhdGUgc2VudGVuY2UubGlzdH0uIFRoaXMgd2lsbCAKIyBjb3N0IDI1LTMwIG1pbnV0ZXMuIFRvIHNhdmUgeW91ciB0aW1lLCB5b3UgY2FuIHNpbXBseSB1c2UgaXQuCiMgRmVlbCBmcmVlIGlmIHlvdSBkb24ndCB3YW50IHRvIHJ1biB7ciBnZW5lcmF0ZSBzZW50ZW5jZS5saXN0fQpzdWJmaWxlIDwtICcuLi9vdXRwdXQvc2VudGVuY2UubGlzdC5jc3YnCnNlbnRlbmNlLmxpc3QgPC0gcmVhZC5jc3Yoc3ViZmlsZSkKYGBgCgoKYGBge3IgLHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CgpyZWR1Y2VkX2RhdGEgPSBmdWxsX2RhdGEgJT4lIHNlbGVjdCh0aXRsZSwgYXV0aG9yLCBzY2hvb2wsIHNlbnRlbmNlX3NwYWN5LCBvcmlnaW5hbF9wdWJsaWNhdGlvbl9kYXRlLCBzZW50ZW5jZV9sZW5ndGgsIHdvcmQuY291bnQpCgojdHJpYWxfZGF0YSA8LSByZWR1Y2VkX2RhdGFbMToxMDAwLF0KZGF0YSA8LSByZWR1Y2VkX2RhdGEgJT4lIGZpbHRlcihzY2hvb2wgPT0gImNhcGl0YWxpc20iIHwgc2Nob29sID09ICJjb21tdW5pc20iKQpgYGAKCgojIyBUYXNrIDE6IEludmVzdGlnYXRlIHRoZSBsZW5ndGggb2Ygc2VudGVuY2VzIG9mIGRpZmZlcmVudCBzY2hvb2xzCgpUaGUgd29yZCDigJxwaGlsb3NvcGh54oCdIGxpdGVyYWxseSBtZWFucyB0aGUg4oCcbG92ZeKAnSAoUGhpbG8gaW4gR3JlZWspIG9mIOKAnHdpc2RvbeKAnSAoU29waGlhKS4gQXMgYW4gb3V0c2lkZXIsIEkgYWx3YXlzIHRoaW5rIHBoaWxvc29waHkgaXMgYSBwcm9mb3VuZCwgb3BhcXVlIHN1YmplY3Qgd2hpY2ggaXMgdmVyeSBjaGFsbGVuZ2luZyB0byBsZWFybi4gSSBiZWxpZXZlIHRoYXQgbWFueSBwZW9wbGUgbGlrZSBtZSB3b3VsZCBwcmVzdXBwb3NlIHRoYXQgc2VudGVuY2VzIGluIHBoaWxvc29waHkgdGV4dHMgdGVuZCB0byBiZSBsb25nZXIgdGhhbiB1c3VhbCBzZW50ZW5jZXMuIEhlbmNlLCBsZXQncyBiZWdpbiBieSBpbnZlc3RpZ2F0aW5nIHRoZSB0aGUgbGVuZ3RoIG9mIHNlbnRlbmNlcyBvZiBkaWZmZXJlbnQgc2Nob29scy4KCkZyb20gdGhpcyBiYXIgcGxvdCwgd2Ugc2VlIHRoYXQgZW1waXJpY2lzbSwgY2FwaXRhbGlzbSwgYW5kIGdlcm1hbl9pZGVhbGlzbSBhcmUgdGhlIHRocmVlIHNjaG9vbHMgd2l0aCBsb25nZXN0IHNlbnRlbmNlcyhsb25nZXIgdGhhbiAzMCB3b3Jkcyk7IE5pZXR6c2NoZSwgYW5hbHl0aWMsIHBsYXRvIGFyZSB0aGUgdGhyZWUgc2Nob29scyB3aXRoIHJlbGF0aXZlIHNob3J0IHNlbnRlbmNlcyhhIGJpZyBsb25nZXIgdGhhbiAyMCB3b3JkcykuICJJbiBnZW5lcmFsLCBhbiBhdmVyYWdlIG9mIDE1IHRvIDIwIHdvcmRzIGlzIGVmZmVjdGl2ZSBmb3IgbW9zdCB0ZWNobmljYWwgY29tbXVuaWNhdGlvbi4iIC0tQnkgSmFtZXMgU2NvdHQuIEhlbmNlLCB3ZSBzZWUgdGhhdCBldmVuIHRoZSBzY2hvb2wgd2l0aCBzaG9ydGVzdCBtZWFuIGxlbmd0aCBvZiBzZW50ZW5jZXMgc3RpbGwgaGFzIG1lYW4gbGVuZ3RoIGxvbmdlciB0aGFuIHVzdWFsIHdyaXR0ZW4gc2VudGVuY2VzJyBsZW5ndGguCgpgYGB7ciAsd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KZGF0YS5ieXNjaG9vbCA8LSByZWR1Y2VkX2RhdGEgJT4lIGdyb3VwX2J5KHNjaG9vbCkgJT4lCiAgc3VtbWFyaXNlKG1lYW5sZW5ndGggPSBtZWFuKHdvcmQuY291bnQpKSAlPiUKICBhcnJhbmdlKG1lYW5sZW5ndGgpCiAgCmcxIDwtIGRhdGEuYnlzY2hvb2wgJT4lIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoc2Nob29sLCBtZWFubGVuZ3RoKSwgeSA9IG1lYW5sZW5ndGgsIGZpbGwgPSBzY2hvb2wpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkJhciBwbG90OiBtZWFuIGxlbmd0aCBvZiBzZW50ZW5jZXMod29yZCBjb3VudCkgb2YgZGlmZmVyZW50IHNjaG9vbHMiLAogICAgeCA9ICJTY2hvb2xzIiwKICAgIHkgPSAiTWVhbiBMZW5ndGggb2YgU2VudGVuY2VzIgogICkgKwogIGNvb3JkX2ZsaXAoKQoKZzEKYGBgCgpJbiBhZGRpdGlvbiB0byB0aGUgbWVhbiBsZW5ndGggb2Ygc2VudGVuY2VzLCB0aGlzIHZpb2xpbiArIGJveCBwbG90IHdpbGwgc2hvdyBtb3JlIGRldGFpbHMgb2YgYWN0dWFsIGRpc3RyaWJ1dGlvbnMgb2Ygc2VudGVuY2UgbGVuZ3RoLiBBbGwgdGhlIHNjaG9vbHMgaGF2ZSBvdXRsaWVycyhibGFjayBkb3RzKSBvbiB0aGUgcmlnaHQgc2lkZSBvZiB2aW9saW4gcGxvdCwgd2hpY2ggbWVhbnMgdGhleSBhbGwgaGF2ZSBzb21lIHZlcnkgbG9uZyBzZW50ZW5jZXMgd2hpY2ggbWlnaHQgYmUgYWJzdHJ1c2Ugb3Igcmlnb3JvdXMuCgpgYGB7ciwgZmlnLndpZHRoID0gMywgZmlnLmhlaWdodCA9IDN9CmRhdGEuYnlzY2hvb2wgPC0gcmVkdWNlZF9kYXRhICU+JSBncm91cF9ieShzY2hvb2wpIApnMiA8LSBkYXRhLmJ5c2Nob29sICU+JSBnZ3Bsb3QoYWVzKHggPSBzY2hvb2wsIHkgPSB3b3JkLmNvdW50LCBmaWxsID0gc2Nob29sKSkgKwogIGdlb21fdmlvbGluKGFscGhhID0gMC41KSArCiAgI2dlb21fcG9pbnQocG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIoc2VlZCA9IDEsIHdpZHRoID0gMC4yKSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGdlb21fYm94cGxvdCh3aWR0aD0uMSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJ2aW9saW4gcGxvdCArIGJveCBwbG90OiBzcHJlYWQgb2Ygc2VudGVuY2VzJyBsZW5ndGggXG4gb2YgZGlmZmVyZW50IHNjaG9vbHMiLAogICAgeCA9ICJTY2hvb2xzIiwKICAgIHkgPSAiTGVuZ3RoIG9mIFNlbnRlbmNlcyIKICApICsKICBjb29yZF9mbGlwKCkKCmcyCmBgYAoKCgoKIyMgVGFzayAyOiBJbnZlc3RpZ2F0ZSB0aGUgZnJlcXVlbnRseSBtZW50aW9uZWQgd29yZHMKCldoYXQgd2UgZGlkIGluIHRhc2sgMSB3b3VsZCBnZW5lcmFsbHkgcmVwcmVzZW50cyB0aGUgc2hhcGUgYW5kIGZvcm1hdCBvZiBzZW50ZW5jZXMgaW4gZGlmZmVyZW50IHNjaG9vbHMuIE5vdywgbGV0J3MgZGlnIGludG8gdGhlIGNvbnRlbnRzIGFuZCB0b3BpY3MuCgpMZXQncyBmaXJzdCBoYXZlIGFuIG92ZXJ2aWV3IG9mIGZyZXF1ZW5jeSBvZiB3b3JkcyBpbiB0aGUgd2hvbGUgY29ycHVzLiBBIHdvcmRjbG91ZCB3b3VsZCBiZSBhbiBvcHRpbWFsIG1ldGhvZCBmb3Igd29yZCBmcmVxdWVuY3kgdmlzdWFsaXphdGlvbi4KCiMjIyMgUHJlcGFyZSBjb3JwdXMKUHV0IGFsbCB0aGUgc2VudGVuY2VzKDM2MDgwOCBvYnNlcnZhdGlvbnMpIGludG8gYSBMYXJnZSBTaW1wbGVDb3JwdXMgZG9jcy4gCmBgYHtyIHByZXBhcmUgY29ycHVzLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CnRleHQgPC0gZnVsbF9kYXRhJHNlbnRlbmNlX2xvd2VyZWQKZG9jcyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKHRleHQpKQpgYGAKCiMjIyMgQ2xlYW4gY29ycHVzIGFuZCBtYWtlIGRvY3VtZW50LXRlcm0tbWF0cmljZXMKKipmLmNsZWFuLmNvcnB1cyoqIGNsZWFucyB0aGUgZG9jcyBieSBsb3dlcmluZyBzZW50ZW5jZXMsIHJlbW92aW5nIG51bWJlcnMsIHB1bmN0dWF0aW9ucywgd2hpdGUgc3BhY2VzLCBjb21tb24gc3RvcCB3b3JkcyBpbiBFbmdsaXNoLCBhbmQgYW4gYWRkaXRpb25hbCBzZXQgb2Ygd29yZHMgcm1fd29yZHMgd2hpY2ggY29udGFpbnMgd29yZHMgb2YgbXkgY2hvaWNlLiAqKmYubWFrZS50ZG0qKiBtYWtlcyB0aGUgZG9jcyByZWFkeSB0byBtYWtlIGEgd29yZGNsb3VkLiBTZWUgZGV0YWlscyBpbiAqLi4vbGliL3dvcmRjbG91ZEZ1bmNzLlIqLgpgYGB7ciBjbGVhbiBjb3JwdXMgYW5kIG1ha2UgdGRtLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpybV93b3JkcyA9IGMoJ2Fsc28nLCAnYXJlYXMnLCAnY2FuJywgJ2V0YycsICdnZXQnLCAnanVzdCcsICdsaWtlJywKJ2xvdCcsICdtYW55JywgJ21heScsICduZWVkJywgJ29uZScsICdzJywgJ3NldCcsICd0JywKJ3RpbWUnLCAndXMnLCAndXNlJywgJ3dheScsICd3ZWxsJywgJ3dpbGwnLCAnYicsICdlJywKJ2cnLCAnbGVzcycsICdnaXZlJywgJ3RlbGwnLCAnaW0nLCAndGFrZScsICdjb21pbmcnLAonc2F5JywgJ3JlYWxseScsICdtdXN0JykKCmRvY3MgPC0gZi5jbGVhbi5jb3JwdXMoZG9jcykKdGRtLm92ZXJhbGwgPC0gZi5tYWtlLnRkbShkb2NzKQpgYGAKCiMjIyMgTWFrZSBhIHdvcmRjbG91ZCBvZiB0aGUgd2hvbGUgY29ycHVzCgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9Niwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0Kd29yZGNsb3VkKHRkbS5vdmVyYWxsJHRlcm0sIHRkbS5vdmVyYWxsJGBzdW0oY291bnQpYCwKICAgICAgICAgIHNjYWxlPWMoNSwwLjgpLAogICAgICAgICAgbWF4LndvcmRzPTIwMCwKICAgICAgICAgIG1pbi5mcmVxPTEsCiAgICAgICAgICByYW5kb20ub3JkZXI9RkFMU0UsCiAgICAgICAgICByb3QucGVyPTAuMywKICAgICAgICAgIHJhbmRvbS5jb2xvcj1GQUxTRSwKICAgICAgICAgIGNvbG9ycz1icmV3ZXIucGFsKDgsIkRhcmsyIikpCmBgYAoKIyMjIyBOb3cgbGV0J3Mgc2VlIHRoZSB3b3JkIGNsb3VkcyBvZiBkaWZmZXJlbnQgc2Nob29scy4KClRoZSBtZXRob2QgaXMgc2ltaWxhciB0byBhYm92ZS4gWW91IGNhbiByZWFkIHRoZSBhY3R1YWwgY29kZSBpbiAqLi4vZG9jL1BoaWxvc29waHkgZGF0YSBzdG9yeS5SbWQqLiAKCkNhcGl0YWxpc206CgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSxlY2hvPUZBTFNFfQp0ZXh0LmNhcGl0YWxpc20gPC0gZnVsbF9kYXRhICU+JSBmaWx0ZXIoc2Nob29sID09ICJjYXBpdGFsaXNtIikKdGV4dC5jYXBpdGFsaXNtIDwtIHRleHQuY2FwaXRhbGlzbSRzZW50ZW5jZV9sb3dlcmVkCmRvY3MgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0LmNhcGl0YWxpc20pKQpkb2NzIDwtIGYuY2xlYW4uY29ycHVzKGRvY3MpCnRkbS5vdmVyYWxsIDwtIGYubWFrZS50ZG0oZG9jcykKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTYsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0Kd29yZGNsb3VkKHRkbS5vdmVyYWxsJHRlcm0sIHRkbS5vdmVyYWxsJGBzdW0oY291bnQpYCwKICAgICAgICAgIHNjYWxlPWMoNSwxLjUpLAogICAgICAgICAgbWF4LndvcmRzPTEwMCwKICAgICAgICAgIG1pbi5mcmVxPTEsCiAgICAgICAgICByYW5kb20ub3JkZXI9RkFMU0UsCiAgICAgICAgICByb3QucGVyPTAuMywKICAgICAgICAgIHJhbmRvbS5jb2xvcj1GQUxTRSwKICAgICAgICAgIGNvbG9ycz1icmV3ZXIucGFsKDksIkJsdWVzIikpCmBgYApFbXBpcmljaXNtOgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0KdGV4dC5lbXBpcmljaXNtIDwtIGZ1bGxfZGF0YSAlPiUgZmlsdGVyKHNjaG9vbCA9PSAiZW1waXJpY2lzbSIpCnRleHQuZW1waXJpY2lzbSA8LSB0ZXh0LmVtcGlyaWNpc20kc2VudGVuY2VfbG93ZXJlZApkb2NzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodGV4dC5lbXBpcmljaXNtKSkKZG9jcyA8LSBmLmNsZWFuLmNvcnB1cyhkb2NzKQp0ZG0ub3ZlcmFsbCA8LSBmLm1ha2UudGRtKGRvY3MpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CndvcmRjbG91ZCh0ZG0ub3ZlcmFsbCR0ZXJtLCB0ZG0ub3ZlcmFsbCRgc3VtKGNvdW50KWAsCiAgICAgICAgICBzY2FsZT1jKDUsMS41KSwKICAgICAgICAgIG1heC53b3Jkcz0xMDAsCiAgICAgICAgICBtaW4uZnJlcT0xLAogICAgICAgICAgcmFuZG9tLm9yZGVyPUZBTFNFLAogICAgICAgICAgcm90LnBlcj0wLjMsCiAgICAgICAgICByYW5kb20uY29sb3I9RkFMU0UsCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg5LCJCbHVlcyIpKQpgYGAKCkdlcm1hbl9pZGVhbGlzbToKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CnRleHQuZ2VybWFuX2lkZWFsaXNtIDwtIGZ1bGxfZGF0YSAlPiUgZmlsdGVyKHNjaG9vbCA9PSAiZ2VybWFuX2lkZWFsaXNtIikKdGV4dC5nZXJtYW5faWRlYWxpc20gPC0gdGV4dC5nZXJtYW5faWRlYWxpc20kc2VudGVuY2VfbG93ZXJlZApkb2NzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodGV4dC5nZXJtYW5faWRlYWxpc20pKQpkb2NzIDwtIGYuY2xlYW4uY29ycHVzKGRvY3MpCnRkbS5vdmVyYWxsIDwtIGYubWFrZS50ZG0oZG9jcykKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTYsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0Kd29yZGNsb3VkKHRkbS5vdmVyYWxsJHRlcm0sIHRkbS5vdmVyYWxsJGBzdW0oY291bnQpYCwKICAgICAgICAgIHNjYWxlPWMoNSwxLjUpLAogICAgICAgICAgbWF4LndvcmRzPTEwMCwKICAgICAgICAgIG1pbi5mcmVxPTEsCiAgICAgICAgICByYW5kb20ub3JkZXI9RkFMU0UsCiAgICAgICAgICByb3QucGVyPTAuMywKICAgICAgICAgIHJhbmRvbS5jb2xvcj1GQUxTRSwKICAgICAgICAgIGNvbG9ycz1icmV3ZXIucGFsKDksIkJsdWVzIikpCmBgYApDb250aW5lbnRhbDoKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CnRleHQuY29udGluZW50YWwgPC0gZnVsbF9kYXRhICU+JSBmaWx0ZXIoc2Nob29sID09ICJjb250aW5lbnRhbCIpCnRleHQuY29udGluZW50YWwgPC0gdGV4dC5jb250aW5lbnRhbCRzZW50ZW5jZV9sb3dlcmVkCmRvY3MgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0LmNvbnRpbmVudGFsKSkKZG9jcyA8LSBmLmNsZWFuLmNvcnB1cyhkb2NzKQp0ZG0ub3ZlcmFsbCA8LSBmLm1ha2UudGRtKGRvY3MpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CndvcmRjbG91ZCh0ZG0ub3ZlcmFsbCR0ZXJtLCB0ZG0ub3ZlcmFsbCRgc3VtKGNvdW50KWAsCiAgICAgICAgICBzY2FsZT1jKDUsMS41KSwKICAgICAgICAgIG1heC53b3Jkcz0xMDAsCiAgICAgICAgICBtaW4uZnJlcT0xLAogICAgICAgICAgcmFuZG9tLm9yZGVyPUZBTFNFLAogICAgICAgICAgcm90LnBlcj0wLjMsCiAgICAgICAgICByYW5kb20uY29sb3I9RkFMU0UsCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg5LCJCbHVlcyIpKQpgYGAKCgpSYXRpb25hbGlzbToKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CnRleHQucmF0aW9uYWxpc20gPC0gZnVsbF9kYXRhICU+JSBmaWx0ZXIoc2Nob29sID09ICJyYXRpb25hbGlzbSIpCnRleHQucmF0aW9uYWxpc20gPC0gdGV4dC5yYXRpb25hbGlzbSRzZW50ZW5jZV9sb3dlcmVkCmRvY3MgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0LnJhdGlvbmFsaXNtKSkKZG9jcyA8LSBmLmNsZWFuLmNvcnB1cyhkb2NzKQp0ZG0ub3ZlcmFsbCA8LSBmLm1ha2UudGRtKGRvY3MpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CndvcmRjbG91ZCh0ZG0ub3ZlcmFsbCR0ZXJtLCB0ZG0ub3ZlcmFsbCRgc3VtKGNvdW50KWAsCiAgICAgICAgICBzY2FsZT1jKDUsMS41KSwKICAgICAgICAgIG1heC53b3Jkcz0xMDAsCiAgICAgICAgICBtaW4uZnJlcT0xLAogICAgICAgICAgcmFuZG9tLm9yZGVyPUZBTFNFLAogICAgICAgICAgcm90LnBlcj0wLjMsCiAgICAgICAgICByYW5kb20uY29sb3I9RkFMU0UsCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg5LCJCbHVlcyIpKQpgYGAKCkFyaXN0b3RsZToKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CnRleHQuYXJpc3RvdGxlIDwtIGZ1bGxfZGF0YSAlPiUgZmlsdGVyKHNjaG9vbCA9PSAiYXJpc3RvdGxlIikKdGV4dC5hcmlzdG90bGUgPC0gdGV4dC5hcmlzdG90bGUkc2VudGVuY2VfbG93ZXJlZApkb2NzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodGV4dC5hcmlzdG90bGUpKQpkb2NzIDwtIGYuY2xlYW4uY29ycHVzKGRvY3MpCnRkbS5vdmVyYWxsIDwtIGYubWFrZS50ZG0oZG9jcykKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTYsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0Kd29yZGNsb3VkKHRkbS5vdmVyYWxsJHRlcm0sIHRkbS5vdmVyYWxsJGBzdW0oY291bnQpYCwKICAgICAgICAgIHNjYWxlPWMoNSwxLjUpLAogICAgICAgICAgbWF4LndvcmRzPTEwMCwKICAgICAgICAgIG1pbi5mcmVxPTEsCiAgICAgICAgICByYW5kb20ub3JkZXI9RkFMU0UsCiAgICAgICAgICByb3QucGVyPTAuMywKICAgICAgICAgIHJhbmRvbS5jb2xvcj1GQUxTRSwKICAgICAgICAgIGNvbG9ycz1icmV3ZXIucGFsKDksIkJsdWVzIikpCmBgYAoKRmVtaW5pc206CgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSxlY2hvPUZBTFNFfQp0ZXh0LmZlbWluaXNtIDwtIGZ1bGxfZGF0YSAlPiUgZmlsdGVyKHNjaG9vbCA9PSAiZmVtaW5pc20iKQp0ZXh0LmZlbWluaXNtIDwtIHRleHQuZmVtaW5pc20kc2VudGVuY2VfbG93ZXJlZApkb2NzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodGV4dC5mZW1pbmlzbSkpCmRvY3MgPC0gZi5jbGVhbi5jb3JwdXMoZG9jcykKdGRtLm92ZXJhbGwgPC0gZi5tYWtlLnRkbShkb2NzKQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9Niwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSxlY2hvPUZBTFNFfQp3b3JkY2xvdWQodGRtLm92ZXJhbGwkdGVybSwgdGRtLm92ZXJhbGwkYHN1bShjb3VudClgLAogICAgICAgICAgc2NhbGU9Yyg1LDEuNSksCiAgICAgICAgICBtYXgud29yZHM9MTAwLAogICAgICAgICAgbWluLmZyZXE9MSwKICAgICAgICAgIHJhbmRvbS5vcmRlcj1GQUxTRSwKICAgICAgICAgIHJvdC5wZXI9MC4zLAogICAgICAgICAgcmFuZG9tLmNvbG9yPUZBTFNFLAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOSwiQmx1ZXMiKSkKYGBgCgpDb21tdW5pc206CgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSxlY2hvPUZBTFNFfQp0ZXh0LmNvbW11bmlzbSA8LSBmdWxsX2RhdGEgJT4lIGZpbHRlcihzY2hvb2wgPT0gImNvbW11bmlzbSIpCnRleHQuY29tbXVuaXNtIDwtIHRleHQuY29tbXVuaXNtJHNlbnRlbmNlX2xvd2VyZWQKZG9jcyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKHRleHQuY29tbXVuaXNtKSkKZG9jcyA8LSBmLmNsZWFuLmNvcnB1cyhkb2NzKQp0ZG0ub3ZlcmFsbCA8LSBmLm1ha2UudGRtKGRvY3MpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CndvcmRjbG91ZCh0ZG0ub3ZlcmFsbCR0ZXJtLCB0ZG0ub3ZlcmFsbCRgc3VtKGNvdW50KWAsCiAgICAgICAgICBzY2FsZT1jKDUsMS41KSwKICAgICAgICAgIG1heC53b3Jkcz0xMDAsCiAgICAgICAgICBtaW4uZnJlcT0xLAogICAgICAgICAgcmFuZG9tLm9yZGVyPUZBTFNFLAogICAgICAgICAgcm90LnBlcj0wLjMsCiAgICAgICAgICByYW5kb20uY29sb3I9RkFMU0UsCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg5LCJCbHVlcyIpKQpgYGAKClBoZW5vbWVub2xvZ3k6IAoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0KdGV4dC5waGVub21lbm9sb2d5IDwtIGZ1bGxfZGF0YSAlPiUgZmlsdGVyKHNjaG9vbCA9PSAicGhlbm9tZW5vbG9neSIpCnRleHQucGhlbm9tZW5vbG9neSA8LSB0ZXh0LnBoZW5vbWVub2xvZ3kkc2VudGVuY2VfbG93ZXJlZApkb2NzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodGV4dC5waGVub21lbm9sb2d5KSkKZG9jcyA8LSBmLmNsZWFuLmNvcnB1cyhkb2NzKQp0ZG0ub3ZlcmFsbCA8LSBmLm1ha2UudGRtKGRvY3MpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CndvcmRjbG91ZCh0ZG0ub3ZlcmFsbCR0ZXJtLCB0ZG0ub3ZlcmFsbCRgc3VtKGNvdW50KWAsCiAgICAgICAgICBzY2FsZT1jKDUsMS41KSwKICAgICAgICAgIG1heC53b3Jkcz0xMDAsCiAgICAgICAgICBtaW4uZnJlcT0xLAogICAgICAgICAgcmFuZG9tLm9yZGVyPUZBTFNFLAogICAgICAgICAgcm90LnBlcj0wLjMsCiAgICAgICAgICByYW5kb20uY29sb3I9RkFMU0UsCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg5LCJCbHVlcyIpKQpgYGAKCnN0b2ljaXNtOiBUaG91IGlzIGFuIG9sZC1mYXNoaW9uZWQsIHBvZXRpYywgb3IgcmVsaWdpb3VzIHdvcmQgZm9yICd5b3UnIHdoZW4geW91IGFyZSB0YWxraW5nIHRvIG9ubHkgb25lIHBlcnNvbi4gSXQgaXMgdXNlZCBhcyB0aGUgc3ViamVjdCBvZiBhIHZlcmIuIEluIHJtX3dvcmRzLCBJIGluY2x1ZGUgInlvdSIgYXMgaXQgaXMgYW4gaW5zaWduaWZpY2FudCB3b3JkLiBCdXQgInRob3UiIGJyaW5ncyBhIHNwZWNpZmljIGNvbnRleHQgYW5kIHN0eWxlIG9mIGEgcGhpbG9zb3BoeSB0ZXh0LgoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0KdGV4dC5zdG9pY2lzbSA8LSBmdWxsX2RhdGEgJT4lIGZpbHRlcihzY2hvb2wgPT0gInN0b2ljaXNtIikKdGV4dC5zdG9pY2lzbSA8LSB0ZXh0LnN0b2ljaXNtJHNlbnRlbmNlX2xvd2VyZWQKZG9jcyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKHRleHQuc3RvaWNpc20pKQpkb2NzIDwtIGYuY2xlYW4uY29ycHVzKGRvY3MpCnRkbS5vdmVyYWxsIDwtIGYubWFrZS50ZG0oZG9jcykKYGBgCgoKYGBge3IsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTYsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0Kd29yZGNsb3VkKHRkbS5vdmVyYWxsJHRlcm0sIHRkbS5vdmVyYWxsJGBzdW0oY291bnQpYCwKICAgICAgICAgIHNjYWxlPWMoNSwxLjUpLAogICAgICAgICAgbWF4LndvcmRzPTEwMCwKICAgICAgICAgIG1pbi5mcmVxPTEsCiAgICAgICAgICByYW5kb20ub3JkZXI9RkFMU0UsCiAgICAgICAgICByb3QucGVyPTAuMywKICAgICAgICAgIHJhbmRvbS5jb2xvcj1GQUxTRSwKICAgICAgICAgIGNvbG9ycz1icmV3ZXIucGFsKDksIkJsdWVzIikpCmBgYAoKQW5hbHl0aWM6CgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSxlY2hvPUZBTFNFfQp0ZXh0LmFuYWx5dGljIDwtIGZ1bGxfZGF0YSAlPiUgZmlsdGVyKHNjaG9vbCA9PSAiYW5hbHl0aWMiKQp0ZXh0LmFuYWx5dGljIDwtIHRleHQuYW5hbHl0aWMkc2VudGVuY2VfbG93ZXJlZApkb2NzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UodGV4dC5hbmFseXRpYykpCmRvY3MgPC0gZi5jbGVhbi5jb3JwdXMoZG9jcykKdGRtLm92ZXJhbGwgPC0gZi5tYWtlLnRkbShkb2NzKQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9Niwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSxlY2hvPUZBTFNFfQp3b3JkY2xvdWQodGRtLm92ZXJhbGwkdGVybSwgdGRtLm92ZXJhbGwkYHN1bShjb3VudClgLAogICAgICAgICAgc2NhbGU9Yyg1LDEuNSksCiAgICAgICAgICBtYXgud29yZHM9MTAwLAogICAgICAgICAgbWluLmZyZXE9MSwKICAgICAgICAgIHJhbmRvbS5vcmRlcj1GQUxTRSwKICAgICAgICAgIHJvdC5wZXI9MC4zLAogICAgICAgICAgcmFuZG9tLmNvbG9yPUZBTFNFLAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOSwiQmx1ZXMiKSkKYGBgCgpOaWV0enNjaGU6IAoKYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsZWNobz1GQUxTRX0KdGV4dC5uaWV0enNjaGUgPC0gZnVsbF9kYXRhICU+JSBmaWx0ZXIoc2Nob29sID09ICJuaWV0enNjaGUiKQp0ZXh0Lm5pZXR6c2NoZSA8LSB0ZXh0Lm5pZXR6c2NoZSRzZW50ZW5jZV9sb3dlcmVkCmRvY3MgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0Lm5pZXR6c2NoZSkpCmRvY3MgPC0gZi5jbGVhbi5jb3JwdXMoZG9jcykKdGRtLm92ZXJhbGwgPC0gZi5tYWtlLnRkbShkb2NzKQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9Niwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSxlY2hvPUZBTFNFfQp3b3JkY2xvdWQodGRtLm92ZXJhbGwkdGVybSwgdGRtLm92ZXJhbGwkYHN1bShjb3VudClgLAogICAgICAgICAgc2NhbGU9Yyg1LDEuNSksCiAgICAgICAgICBtYXgud29yZHM9MTAwLAogICAgICAgICAgbWluLmZyZXE9MSwKICAgICAgICAgIHJhbmRvbS5vcmRlcj1GQUxTRSwKICAgICAgICAgIHJvdC5wZXI9MC4zLAogICAgICAgICAgcmFuZG9tLmNvbG9yPUZBTFNFLAogICAgICAgICAgY29sb3JzPWJyZXdlci5wYWwoOSwiQmx1ZXMiKSkKYGBgCgpQbGF0bzoKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CnRleHQucGxhdG8gPC0gZnVsbF9kYXRhICU+JSBmaWx0ZXIoc2Nob29sID09ICJwbGF0byIpCnRleHQucGxhdG8gPC0gdGV4dC5wbGF0byRzZW50ZW5jZV9sb3dlcmVkCmRvY3MgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0LnBsYXRvKSkKZG9jcyA8LSBmLmNsZWFuLmNvcnB1cyhkb2NzKQp0ZG0ub3ZlcmFsbCA8LSBmLm1ha2UudGRtKGRvY3MpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLGVjaG89RkFMU0V9CndvcmRjbG91ZCh0ZG0ub3ZlcmFsbCR0ZXJtLCB0ZG0ub3ZlcmFsbCRgc3VtKGNvdW50KWAsCiAgICAgICAgICBzY2FsZT1jKDUsMS41KSwKICAgICAgICAgIG1heC53b3Jkcz0xMDAsCiAgICAgICAgICBtaW4uZnJlcT0xLAogICAgICAgICAgcmFuZG9tLm9yZGVyPUZBTFNFLAogICAgICAgICAgcm90LnBlcj0wLjMsCiAgICAgICAgICByYW5kb20uY29sb3I9RkFMU0UsCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg5LCJCbHVlcyIpKQpgYGAKCkZyb20gdGhlc2Ugd29yZGNsb3VkcywgeW91IGNhbiBmaW5kIG91dCB3aGF0IHdvcmRzIGFyZSBmcmVxdWVudGx5IG1lbnRpb25lZCBpbiBlYWNoIHNjaG9vbCBvZiBwaGlsb3NvcGh5LiBBbmQgeW91IGNhbiBpbWFnaW5lIHdoYXQgdG9waWNzIHRoZXkgZm9jdXMgb24uIEZvciBteSBwZXJzb25hbCBpbnRlcmVzdCwgSSBlc3BlY2lhbGx5IGFuYWx5emUgdGhlIHdvcmRjbG91ZHMgb2YgKipjYXBpdGFsaXNtKiogYW5kICoqY29tbXVuaXNtKiouIE1hbnkgb2YgdXMga25vdyB0aGV5IGFyZSBjb250cmFzdCB0byBzb21lIGRlZ3JlZSwgYnV0IGNhbm5vdCBzdGF0ZSB0aGUgZGlmZmVyZW5jZXMgY2xlYXJseS4gSSBvcmlnaW5hbGx5IGV4cGVjdGVkIHRoZWlyIHdvcmRjbG91ZHMgd291bGQgYmUgdmVyeSBkaWZmZXJlbnQuIEhvd2V2ZXIsIGJvdGggb2YgdGhlbSBtZW50aW9uZWQgYSBsb3QgYWJvdXQgInZhbHVlIiwgImxhYm91ciIsICJjYXBpdGFsIiwgImNvbW1vZGl0aWVzIiwgInByaWNlIiwgIndhZ2VzIiwgInRyYWRlIiBldGMuLiBUaGUgZGVncmVlIG9mIHNpbWlsYXJpdHkgZXhjZWVkZWQgbXkgZXhwZWN0YXRpb24sIGFuZCBJIGJlZ2FuIHRvIHNwZWN1bGF0ZSB0aGF0IHRoZXkgbWlnaHQgb2Z0ZW4gdGFsayBhYm91dCBzaW1pbGFyIHRvcGljIGJ1dCB3aXRoIGNvbnRyYXN0IGlkZWFzLiBIZXJlLCB3ZSBjYW4gcmVmZXIgdG8gQWRhbSBTbWl0aCwgdGhlIHJlbm93bmVkIFNjb3R0aXNoIEVjb25vbWlzdChvbiB0aGUgc2lkZSBvZiBjYXBpdGFsaXNtKSwgYW5kIEthcmwgTWFyeCwgYSBmYW1vdXMgUGhpbG9zb3BoZXIsIGFuZCBTb2Npb2xvZ2lzdCwgZnJvbSBHZXJtYW55KG9uIHRoZSBzaWRlIG9mIGNvbW11bmlzbSksIHRvIHNlZSB0aGUgZGlmZmVyZW5jZSBvZiAqKmNhcGl0YWxpc20qKiBhbmQgKipjb21tdW5pc20qKjoKCioiQ2FwaXRhbGlzbSBpcyBhbiBlY29ub21pYyBzeXN0ZW0gaW4gd2hpY2ggdGhlIHRyYWRlIGFuZCBpbmR1c3RyeSBvZiB0aGUgZWNvbm9teSBpcyBvd25lZCBhbmQgY29udHJvbGxlZCBieSBwcml2YXRlIGluZGl2aWR1YWxzLCB0byBtYWtlIHByb2ZpdC4iKgoKKiJDb21tdW5pc20gcmVmZXJzIHRvIHNvY2lhbCBzeXN0ZW0gaW4gd2hpY2ggY291bnRyeSdzIHRyYWRlIGFuZCBpbmR1c3RyeSBhcmUgY29udHJvbGxlZCBieSB0aGUgY29tbXVuaXR5IGFuZCB0aGUgc2hhcmUgb2YgZWFjaCBpbmRpdmlkdWFsIHJlbGllcyBvbiBoaXMgYWJpbGl0eSBhbmQgbmVlZHMuIioKCkZvciBtb3JlIGRldGFpbCwgcGxlYXNlIHJlZmVyIHRvIFtEaWZmZXJlbmNlIEJldHdlZW4gQ2FwaXRhbGlzbSBhbmQgQ29tbXVuaXNtXShodHRwczovL2tleWRpZmZlcmVuY2VzLmNvbS9kaWZmZXJlbmNlLWJldHdlZW4tY2FwaXRhbGlzbS1hbmQtY29tbXVuaXNtLmh0bWwjOn46dGV4dD1DYXBpdGFsaXNtJTIwaXMlMjBhbiUyMGVjb25vbWljJTIwc3lzdGVtLG9uJTIwaGlzJTIwYWJpbGl0eSUyMGFuZCUyMG5lZWRzLikgSW4gcGFydCAyLCB3ZSB3aWxsIGRvIHNvbWUgc2VudGltZW50IGFuYWx5c2lzIG9uIHRoZXNlIHR3byBzY2hvb2xzIG9mIHBoaWxvc29waHksIGFuZCB0cnkgdG8gZXhwbG9yZSBzb21ldGhpbmcgaW50ZXJlc3RpbmcgYW5kIHVuY292ZXJlZCBieSB0aGUgYWJvdmUgYXJ0aWNsZS4KCiMgUGFydCAyOiBTZW50aW1lbnQgYW5hbHlzaXMgb24gY2FwaXRhbGlzbSBhbmQgY29tbXVuaXNtCgpEdXJpbmcgdGhpcyBwYXJ0LCB3ZSBhcHBseSBzZW50aW1lbnQgYW5hbHlzaXMgdXNpbmcgW05SQyBXb3JkLUVtb3Rpb24gQXNzb2NpYXRpb24gTGV4aWNvbl0oaHR0cDovL3NhaWZtb2hhbW1hZC5jb20vV2ViUGFnZXMvTlJDLUVtb3Rpb24tTGV4aWNvbi5odG0pLiBGb3IgZWFjaCBzZW50ZW5jZSwgdGhpcyBtZXRob2Qgd291bGQgZ2l2ZSBhIHNjb3JlIGZvciBlYWNoIHNlbnRpbWVudCgiYW5nZXIiLCAiYW50aWNpcGF0aW9uIiwgImRpc2d1c3QiLCAiZmVhciIsICJqb3kiLCAic2FkbmVzcyIsICJzdXJwcmlzZSIsICJ0cnVzdCIsICJuZWdhdGl2ZSIsICJwb3NpdGl2ZSIpIGFjY29yZGluZyB0byBUaGUgTlJDIEVtb3Rpb24gTGV4aWNvbiwgYSBsaXN0IG9mIEVuZ2xpc2ggd29yZHMgYW5kIHRoZWlyIGFzc29jaWF0aW9ucyB3aXRoIGJhc2ljIGVtb3Rpb25zLiAKCiMjIHRhc2sgMyA6IEludmVzdGlnYXRlIGFuZCBjb21wYXJlIGVtb3Rpb25zIGJldHdlZW4gY2FwaXRhbGlzbSBhbmQgY29tbXVuaXNtCgojIyMjIGdlbmVyYXRlIHNlbnRlbmNlLmxpc3QKc2VudGVuY2UubGlzdCBpcyBhIHN1YnNldCBvZiB0aGUgd2hvbGUgY29ycHVzLiBJdCBvbmx5IGluY2x1ZGVzIHNlbnRlbmNlcyB3aXRoIHNjaG9vbCBvZiBjYXBpdGFsaXNtIG9yIGNvbW11bmlzbS4gQW5kIHdlIHdpbGwgZ2VuZXJhdCB0aGVpciBzZW50aW1lbnQgc2NvcmUgYW5kIGFwcGVuZCB0aGVtIG9uIHRoZSByaWdodCBvZiB0aGUgZGF0YSBzZXQoMTIgY29sdW1uczogMTAgY29sdW1ucyBvZiBzZW50aW1lbnQsIDEgY29sdW1uIG9mIHNlbnRlbmNlIGlkLCAxIGNvbHVtbiBvZiB3b3JkIGNvdW50KS4gSXQgd2lsbCBjb3N0IDI1LTMwIG1pbnV0ZXMgdG8gZ2VuZXJhdGUgc2VudGVuY2UubGlzdCwgc28gSSBjb21tZW50ZWQgdGhpcyByIGNodW5rIGFuZCB5b3UgY2FuIHVzZSBpdCBmcm9tICoiLi4vbGliL3dvcmRjbG91ZEZ1bmNzLlIiKi4KCmBgYHtyIGdlbmVyYXRlIHNlbnRlbmNlLmxpc3QsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMgc2VudGVuY2UubGlzdD1OVUxMCiMgCiMgZm9yKGkgaW4gMTpucm93KGRhdGEpKXsKIyAgIHNlbnRlbmNlcyA8LSBkYXRhJHNlbnRlbmNlX3NwYWN5W2ldCiMgICBpZihsZW5ndGgoc2VudGVuY2VzKT4wKXsKIyAgICAgZW1vdGlvbnM9Z2V0X25yY19zZW50aW1lbnQoc2VudGVuY2VzKQojICAgICAjd29yZC5jb3VudD13b3JkX2NvdW50KHNlbnRlbmNlcykKIyAgICAgIyBjb2xuYW1lcyhlbW90aW9ucyk9cGFzdGUwKCJlbW8uIiwgY29sbmFtZXMoZW1vdGlvbnMpKQojICAgICAjIGluIGNhc2UgdGhlIHdvcmQgY291bnRzIGFyZSB6ZXJvcz8KIyAgICAgI2Vtb3Rpb25zPWRpYWcoMS8odHJpYWxfZGF0YSRzZW50ZW5jZV9sZW5ndGhbMV0rMC4wMSkpJSolYXMubWF0cml4KGVtb3Rpb25zKQojICAgICBlbW90aW9ucyA9IGFzLm1hdHJpeChlbW90aW9ucykKIyAgICAgc2VudGVuY2UubGlzdD1yYmluZChzZW50ZW5jZS5saXN0LAojICAgICAgICAgICAgICAgICAgICAgICAgIGNiaW5kKGRhdGFbaSxdLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbnRlbmNlcz1hcy5jaGFyYWN0ZXIoc2VudGVuY2VzKSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjd29yZC5jb3VudCwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbW90aW9ucywKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZW50LmlkPWkKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApCiMgICAgICkKIyAgIH0KIyB9CiMKIyBzZW50ZW5jZS5saXN0IDwtIHNlbnRlbmNlLmxpc3QgJT4lIGxlZnRfam9pbihkYXRhKSAjam9pbiB0aGUgd29yZC5jb3VudCBpbnRvIHNlbnRlbmNlLmxpc3QKI3dyaXRlLmNzdihzZW50ZW5jZS5saXN0LCIvVXNlcnMvaml1cnV3YW5nL0RvY3VtZW50cy9HaXRIdWIvc3ByaW5nLTIwMjItcHJqMS1qcndhbmcwODEwL291dHB1dC9zZW50ZW5jZS5saXN0LmNzdiIpCmBgYAoKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpuYW1lcyhzZW50ZW5jZS5saXN0KQpgYGAKCiMjIyMgRmluZCBvdXQgZW1vdGlvbmFsbHkgY2hhcmdlZCBzZW50ZW5jZXMKCkhlcmUgd2UgY2FuIHNlZSBzb21lIHR5cGljYWwgc2hvcnQgc2VudGVuY2VzIHdpdGggc3Ryb25nIHNlbnRpbWVudC4KCkNhcGl0YWxpc206CmBgYHtyfQplbW90aW9ucy50eXBlcz1jKCJhbnRpY2lwYXRpb24iLCAiam95IiwgInN1cnByaXNlIiwgInRydXN0IiwKICAgICAgICAgICAgICAgICAiYW5nZXIiLCAiZGlzZ3VzdCIsICJmZWFyIiwgInNhZG5lc3MiLCAibmVnYXRpdmUiLCAicG9zaXRpdmUiKQoKc3BlZWNoLmRmPXRibF9kZihzZW50ZW5jZS5saXN0KSAlPiUKICBmaWx0ZXIoc2Nob29sID09ICJjYXBpdGFsaXNtIiwgd29yZC5jb3VudCA8IDIwKSAlPiUKICBzZWxlY3Qoc2VudGVuY2VzLCBhbmdlcjpwb3NpdGl2ZSkKc3BlZWNoLmRmPWFzLmRhdGEuZnJhbWUoc3BlZWNoLmRmKQphcy5jaGFyYWN0ZXIoc3BlZWNoLmRmJHNlbnRlbmNlc1thcHBseShzcGVlY2guZGZbLC0xXSwgMiwgd2hpY2gubWF4KV0pCmBgYAoKQ29tbXVuaXNtOgpgYGB7cn0KCnNwZWVjaC5kZj10YmxfZGYoc2VudGVuY2UubGlzdCkgJT4lCiAgZmlsdGVyKHNjaG9vbCA9PSAiY29tbXVuaXNtIiwgd29yZC5jb3VudCA8IDIwKSAlPiUKICBzZWxlY3Qoc2VudGVuY2VzLCBhbmdlcjpwb3NpdGl2ZSkKc3BlZWNoLmRmPWFzLmRhdGEuZnJhbWUoc3BlZWNoLmRmKQphcy5jaGFyYWN0ZXIoc3BlZWNoLmRmJHNlbnRlbmNlc1thcHBseShzcGVlY2guZGZbLC0xXSwgMiwgd2hpY2gubWF4KV0pCmBgYAoKIyMjIyBDbHVzdGVyaW5nIG9mIGVtb3Rpb25zCgpIZXJlIGFyZSB0aGUgaGVhdG1hcHMgb2YgY29ycmVsYXRpb24gbWF0cml4IGFib3V0IHNlbnRpbWVudCByZXNwZWN0aXZlbHkgaW4gY2FwaXRhbGlzbSBhbmQgY29tbXVuaXNtLiBQbGVhc2Ugbm90ZSB0aGF0IHRoZSByZWQgcmVnaW9ucyBtZWFucyBhIHN0cm9uZyBwb3NpdGl2ZSBjb3JyZWxhdGlvbihjbG9zZSB0byBidXQgbGVzcyBvciBlcXVhbCB0byAxKSBvZiB0d28gc2VudGltZW50LCBibHVlIHJlZ2lvbnMgbWVhbnMgbmVhcmx5IG5vIGNvcnJlbGF0aW9uKGNsb3NlIHRvIGJ1dCBtb3JlIG9yIGVxdWFsIHRvIDApLCBhbmQgYSB3aGl0ZSByZWdpb24gc2hvd3Mgc29tZSBjb3JyZWxhdGlvbi4KCkNhcGl0YWxpc206CmBgYHtyfQpoZWF0bWFwLjIoY29yKHNlbnRlbmNlLmxpc3QlPiVmaWx0ZXIoc2Nob29sPT0iY2FwaXRhbGlzbSIpJT4lc2VsZWN0KGFuZ2VyOnBvc2l0aXZlKSksIAogICAgICAgICAgc2NhbGUgPSAibm9uZSIsIAogICAgICAgICAgY29sID0gYmx1ZXJlZCgxMDApLCAsIG1hcmdpbj1jKDYsIDYpLCBrZXk9RiwKICAgICAgICAgIHRyYWNlID0gIm5vbmUiLCBkZW5zaXR5LmluZm8gPSAibm9uZSIpCnBhcihtYXI9Yyg0LCA2LCAyLCAxKSkKYGBgCgpDb21tdW5pc206CmBgYHtyfQpoZWF0bWFwLjIoY29yKHNlbnRlbmNlLmxpc3QlPiVmaWx0ZXIoc2Nob29sPT0iY29tbXVuaXNtIiklPiVzZWxlY3QoYW5nZXI6cG9zaXRpdmUpKSwgCiAgICAgICAgICBzY2FsZSA9ICJub25lIiwgCiAgICAgICAgICBjb2wgPSBibHVlcmVkKDEwMCksICwgbWFyZ2luPWMoNiwgNiksIGtleT1GLAogICAgICAgICAgdHJhY2UgPSAibm9uZSIsIGRlbnNpdHkuaW5mbyA9ICJub25lIikKcGFyKG1hcj1jKDQsIDYsIDIsIDEpKQpgYGAKCldlIHNlZSB0aGF0IGZvciBib3RoIHNjaG9vbCwgdGhlaXIgaGVhdG1hcCBhcmUgdmVyeSBzaW1pbGFyLiBJdCBtYWtlcyBzZW5zZSB0aGF0IG1vc3QgcG9zaXRpdmUgc2VudGltZW50cyBhcmUgdW5jb3JyZWxhdGVkIHdpdGggbW9zdCBuZWdhdGl2ZSBzZW50aW1lbnQuIEJ1dCBpdCBpcyBoYXJkIHRvIHRlbGwgYW55IHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYmV0d2VlbiB0d28gc2Nob29scy4gU28sIGxldCdzIGdvIHdpdGggc29tZSBtb3JlIGludHVpdGlvbmlzdGljIG1ldGhvZHMuCgojIyMjIEJhciBwbG90IGFuZCBQaWUgY2hhcnQgb2YgZW1vdGlvbnMKCkhlcmUgYXJlIHRoZSBiYXIgcGxvdCBvZiBtZWFuIHNjb3JlIG9mIGVhY2ggc2VudGltZW50LCBhbmQgdGhlIHBpZSBjaGFydCBvZiBwZXJjZW50YWdlIG9mIGVhY2ggc2VudGltZW50LiBJbiB0aGUgYmFyIHBsb3QsIGFsbCBwb3NpdGl2ZS1yZWxhdGVkIHNlbnRpbWVudHMgYXJlIGluIG9yYW5nZSwgYW5kIGFsbCBuZWdhdGl2ZS1yZWxhdGVkIHNlbnRpbWVudHMgYXJlIGluIHRoZWlyIGFwcHJvcHJpYXRlIGNvbG9yLgoKYGBge3J9CnNlbnRlbmNlLmxpc3QuY2FwaXRhbGlzbSA8LSBzZW50ZW5jZS5saXN0ICU+JSBmaWx0ZXIoc2Nob29sPT0iY2FwaXRhbGlzbSIpCmVtby5tZWFuczE9Y29sTWVhbnMoc2VsZWN0KHNlbnRlbmNlLmxpc3QuY2FwaXRhbGlzbSwgYW5nZXI6cG9zaXRpdmUpPjAuMDEpCmNvbC51c2UxPWMoInJlZDIiLCAiZGFya2dvbGRlbnJvZDEiLCAiY2hhcnRyZXVzZTMiLCJibHVldmlvbGV0IiwgImRhcmtnb2xkZW5yb2QxIiwgImRvZGdlcmJsdWUzIiwgImRhcmtnb2xkZW5yb2QxIiwgImRhcmtnb2xkZW5yb2QxIiwgImJsYWNrIiwgImRhcmtnb2xkZW5yb2QxIikKYmFycGxvdChlbW8ubWVhbnMxW29yZGVyKGVtby5tZWFuczEpXSwgbGFzPTIsIGNvbD1jb2wudXNlMVtvcmRlcihlbW8ubWVhbnMxKV0sIGhvcml6PVQsCiAgICAgICAgY2V4Lm5hbWVzPTAuNywgbWFpbj0iQ2FwaXRhbGlzbSIpCmBgYAoKYGBge3J9CnNlbnRpbWVudC5kZjEgPC0gZGF0YS5mcmFtZSgKICBncm91cD1jKCJhbmdlciIsICJhbnRpY2lwYXRpb24iLCAiZGlzZ3VzdCIsImZlYXIiLCAiam95IiwgInNhZG5lc3MiLCAic3VycHJpc2UiLCAidHJ1c3QiLCAibmVnYXRpdmUiLCAicG9zaXRpdmUiKSwKICB2YWx1ZT1lbW8ubWVhbnMxCikKCnNlbnRpbWVudC5kZjEgPC0gc2VudGltZW50LmRmMSAlPiUgCiAgbXV0YXRlKHBlcmMgPSB2YWx1ZSAvIHN1bSh2YWx1ZSkpICU+JSAKICBhcnJhbmdlKHBlcmMpICU+JQogIG11dGF0ZShsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQocGVyYykpCgoKZ2dwbG90KHNlbnRpbWVudC5kZjEsIGFlcyh4PSIiLCB5PXBlcmMsIGZpbGw9Z3JvdXApKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0xLCBjb2xvcj0id2hpdGUiKSArCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydD0wKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGxhYmVscyksIAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwKICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiLCBzaXplPTMpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJTcGVjdHJhbCIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiUGVyY2VudGFnZSBvZiB0aGUgc2VudGltZW50IGluIENhcGl0YWxpc20iLAogICAgeCA9ICIiLAogICAgeSA9ICIiLAogICkKYGBgCgoKCgoKYGBge3J9CnNlbnRlbmNlLmxpc3QuY29tbXVuaXNtIDwtIHNlbnRlbmNlLmxpc3QgJT4lIGZpbHRlcihzY2hvb2w9PSJjb21tdW5pc20iKQplbW8ubWVhbnMyPWNvbE1lYW5zKHNlbGVjdChzZW50ZW5jZS5saXN0LmNvbW11bmlzbSwgYW5nZXI6cG9zaXRpdmUpPjAuMDEpCmNvbC51c2UyPWMoInJlZDIiLCAiZGFya2dvbGRlbnJvZDEiLCAiY2hhcnRyZXVzZTMiLCJibHVldmlvbGV0IiwgImRhcmtnb2xkZW5yb2QxIiwgImRvZGdlcmJsdWUzIiwgImRhcmtnb2xkZW5yb2QxIiwgImRhcmtnb2xkZW5yb2QxIiwgImJsYWNrIiwgImRhcmtnb2xkZW5yb2QxIikKYmFycGxvdChlbW8ubWVhbnMyW29yZGVyKGVtby5tZWFuczIpXSwgbGFzPTIsIGNvbD1jb2wudXNlMltvcmRlcihlbW8ubWVhbnMyKV0sIGhvcml6PVQsCiAgICAgICAgY2V4Lm5hbWVzPTAuNywgbWFpbj0iQ29tbXVuaXNtIikKYGBgCgoKYGBge3J9CnNlbnRpbWVudC5kZjIgPC0gZGF0YS5mcmFtZSgKICBncm91cD1jKCJhbmdlciIsICJhbnRpY2lwYXRpb24iLCAiZGlzZ3VzdCIsImZlYXIiLCAiam95IiwgInNhZG5lc3MiLCAic3VycHJpc2UiLCAidHJ1c3QiLCAibmVnYXRpdmUiLCAicG9zaXRpdmUiKSwKICB2YWx1ZT1lbW8ubWVhbnMyCikKCnNlbnRpbWVudC5kZjIgPC0gc2VudGltZW50LmRmMiAlPiUgCiAgbXV0YXRlKHBlcmMgPSB2YWx1ZSAvIHN1bSh2YWx1ZSkpICU+JSAKICBhcnJhbmdlKHBlcmMpICU+JQogIG11dGF0ZShsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQocGVyYykpCgoKZ2dwbG90KHNlbnRpbWVudC5kZjIsIGFlcyh4PSIiLCB5PXBlcmMsIGZpbGw9Z3JvdXApKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0xLCBjb2xvcj0id2hpdGUiKSArCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydD0wKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGxhYmVscyksIAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwKICAgICAgICAgICAgc2hvdy5sZWdlbmQgPSBGQUxTRSwKICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiLCBzaXplPTMpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJTcGVjdHJhbCIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiUGVyY2VudGFnZSBvZiB0aGUgc2VudGltZW50IGluIENvbW11bmlzbSIsCiAgICB4ID0gIiIsCiAgICB5ID0gIiIsCiAgKQpgYGAKClRoZXNlIHBsb3RzIHN0aWxsIGxvb2tzIHNpbWlsYXIsIGJ1dCBub3cgd2UgY2FuIGZpbmQgc29tZSBpbnRlcmVzdGluZyBwYXR0ZXJuLiBJbiBjYXBpdGFsaXNtLCAqKmpveSoqIGlzIG11Y2ggaGlnaGVyIHRoYW4gKipmZWFyKio7IGJ1dCAqKmpveSoqIGlzIGxvd2VyIHRoYW4gKipmZWFyKiogaW4gY29tbXVuaXNtLiBJdCBsb29rcyBsaWtlIHNlbnRlbmNlcyBpbiBjb21tdW5pc20gYXJlIG1vcmUgbGlrZWx5IHRvIGV4cHJlc3MgKipmZWFyKiogdGhhbiBpbiBjYXBpdGFsaXNtLiBIb3dldmVyLCBpcyB0aGlzIHRoZSB0cnV0aD8KCkxldCdzIGNvbXBhcmUgdGhlIG1lYW4gc2VudGltZW50IHNjb3JlIG9mIGNhcGl0YWxpc20gYW5kIGNvbW11bmlzbSBieSBjb21iaW5pbmcgdGhlIHR3byBiYXIgcGxvdC4gSGVyZSB3ZSBmaW5kIGEgcmVhbGx5IGludGVyZXN0aW5nIHBvaW50LS0tLS0tICoqZmVhcioqIHNjb3JlIGlzIGFjdHVhbGx5IHNsaWdodGx5IGhpZ2hlciBpbiBjYXBpdGFsaXNtIHRoYW4gaW4gY29tbXVuaXNtLiBTbyB3aGF0IGhhcHBlbmVkPyBUaGUgdHJ1dGggaXMgdGhhdCBzZW50ZW5jZXMgaW4gY2FwaXRhbGlzbSBhcmUgbW9zdGx5IG1vcmUgZW1vdGlvbmFsIHRoYW4gc2VudGVuY2VzIGluIGNvbW11bmlzbS4gVGhlIG9ubHkgZXhjZXB0aW9uIGlzICoqZGlzZ3VzdCoqLiAKCgpgYGB7cn0Kc2VudGltZW50LmRmLmFsbCA8LSBkYXRhLmZyYW1lKAogIGdyb3VwPWMoImFuZ2VyIiwgImFudGljaXBhdGlvbiIsICJkaXNndXN0IiwiZmVhciIsICJqb3kiLCAic2FkbmVzcyIsICJzdXJwcmlzZSIsICJ0cnVzdCIsICJuZWdhdGl2ZSIsICJwb3NpdGl2ZSIpLAogIGNhcGl0YWxpc209ZW1vLm1lYW5zMSwKICBjb21tdW5pc209ZW1vLm1lYW5zMgopCgpzZW50aW1lbnQuZGYuYWxsLmxvbmcgPC0gc2VudGltZW50LmRmLmFsbCAlPiUgcGl2b3RfbG9uZ2VyKGMoImNhcGl0YWxpc20iLCAiY29tbXVuaXNtIikpCgpnMyA8LSBzZW50aW1lbnQuZGYuYWxsLmxvbmcgJT4lIGdncGxvdChhZXMoeCA9IGdyb3VwLCB5ID0gdmFsdWUsIGZpbGwgPSBuYW1lKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnMoCiAgICB4ID0gIiIsCiAgICB5ID0gIm1lYW4gc2NvcmUgb2Ygc2VudGltZW50IiwKICAgIHRpdGxlID0gIlNlbnRpbWVudCBjb21wYXJpc29uOiBDYXBpdGFsaXNtIHZzLiBDb21tdW5pc20iCiAgKQoKZzMKYGBgCgpKdXN0IGZvciB5b3VyIGN1cmlvdXMsIEkgbWFkZSBhIGJhciBwbG90IG9mIG1lYW4gc2VudGltZW50IHNjb3JlIGZvciBlYWNoIGF1dGhvcnMgaW4gY2FwaXRhbGlzbSBhbmQgY29tbXVuaXNtLiBJdCBpcyByZWFsbHkgZnVubnkgdG8gc2VlIHRoYXQgTWFyeCBpcyBzdWNoIGFuIGltcGFzc2l2ZSBwZXJzb24uCgpgYGB7ciwgZWNobz1GQUxTRX0Kc2VudGVuY2UubGlzdC5NYXJ4IDwtIHNlbnRlbmNlLmxpc3QgJT4lIGZpbHRlcihhdXRob3I9PSJNYXJ4IikKZW1vLm1lYW5zLk1hcng9Y29sTWVhbnMoc2VsZWN0KHNlbnRlbmNlLmxpc3QuTWFyeCwgYW5nZXI6cG9zaXRpdmUpPjAuMDEpCgpzZW50ZW5jZS5saXN0LkxlbmluIDwtIHNlbnRlbmNlLmxpc3QgJT4lIGZpbHRlcihhdXRob3I9PSJMZW5pbiIpCmVtby5tZWFucy5MZW5pbj1jb2xNZWFucyhzZWxlY3Qoc2VudGVuY2UubGlzdC5MZW5pbiwgYW5nZXI6cG9zaXRpdmUpPjAuMDEpCgpzZW50ZW5jZS5saXN0LlNtaXRoIDwtIHNlbnRlbmNlLmxpc3QgJT4lIGZpbHRlcihhdXRob3I9PSJTbWl0aCIpCmVtby5tZWFucy5TbWl0aD1jb2xNZWFucyhzZWxlY3Qoc2VudGVuY2UubGlzdC5TbWl0aCwgYW5nZXI6cG9zaXRpdmUpPjAuMDEpCgpzZW50ZW5jZS5saXN0LlJpY2FyZG8gPC0gc2VudGVuY2UubGlzdCAlPiUgZmlsdGVyKGF1dGhvcj09IlJpY2FyZG8iKQplbW8ubWVhbnMuUmljYXJkbz1jb2xNZWFucyhzZWxlY3Qoc2VudGVuY2UubGlzdC5SaWNhcmRvLCBhbmdlcjpwb3NpdGl2ZSk+MC4wMSkKCnNlbnRlbmNlLmxpc3QuS2V5bmVzIDwtIHNlbnRlbmNlLmxpc3QgJT4lIGZpbHRlcihhdXRob3I9PSJLZXluZXMiKQplbW8ubWVhbnMuS2V5bmVzPWNvbE1lYW5zKHNlbGVjdChzZW50ZW5jZS5saXN0LktleW5lcywgYW5nZXI6cG9zaXRpdmUpPjAuMDEpCgpzZW50aW1lbnQuZGYuYnlhdXRob3IgPC0gZGF0YS5mcmFtZSgKICBncm91cD1jKCJhbmdlciIsICJhbnRpY2lwYXRpb24iLCAiZGlzZ3VzdCIsImZlYXIiLCAiam95IiwgInNhZG5lc3MiLCAic3VycHJpc2UiLCAidHJ1c3QiLCAibmVnYXRpdmUiLCAicG9zaXRpdmUiKSwKICBNYXJ4PWVtby5tZWFucy5NYXJ4LAogIExlbmluPWVtby5tZWFucy5MZW5pbiwKICBTbWl0aD1lbW8ubWVhbnMuU21pdGgsCiAgUmljYXJkbz1lbW8ubWVhbnMuUmljYXJkbywKICBLZXluZXM9ZW1vLm1lYW5zLktleW5lcwopCgpzZW50aW1lbnQuZGYuYnlhdXRob3IubG9uZyA8LSBzZW50aW1lbnQuZGYuYnlhdXRob3IgJT4lIHBpdm90X2xvbmdlcihjKCJNYXJ4IiwgIkxlbmluIiwgIlNtaXRoIiwgIlJpY2FyZG8iLCAiS2V5bmVzIiApKQoKZzQgPC0gc2VudGltZW50LmRmLmJ5YXV0aG9yLmxvbmcgJT4lIGdncGxvdChhZXMoeCA9IGdyb3VwLCB5ID0gdmFsdWUsIGZpbGwgPSBuYW1lKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnMoCiAgICB4ID0gIiIsCiAgICB5ID0gIm1lYW4gc2NvcmUgb2Ygc2VudGltZW50IiwKICAgIHRpdGxlID0gIlNlbnRpbWVudCBjb21wYXJpc29uOiBhbGwgdGhlIGF1dGhvcnMiLAogICAgc3VidGl0bGUgPSAiQ29tbXVuaXNtOiBNYXJ4LCBMZW5pbiBcbkNhcGl0YWxpc206IEtleW5lcywgUmljYXJkbywgU21pdGgiCiAgKQoKZzQKCmBgYAoKVGhhdCdzIGFsbCBvZiB0aGUgcGhpbG9zb3BoeSBkYXRhIHN0b3J5LiBJIGhvcGUgeW91IGhhdmUgZnVuIHJlYWRpbmcgaXQhCgo=